// components/calendar/calendar.js

function getDateArr(str, min) {
  // 以 '-'、':'、空格 为分隔符，分割字符串，分割结果得到一个 年月日时分秒 数组
  let arr = str.split(/[-:\s+]/g),
      reg = /^[0-9]*$/
  let rtnArr = []
  arr.forEach(item => {
    if(reg.test(item)) rtnArr.push(item)
  })
  if(rtnArr[0]) {
    for(let i = 0, len = 6 - rtnArr.length; i < len; i++) {
      rtnArr.push('')
    }
    // 年份
    rtnArr[0] = Number(rtnArr[0])
    // 月份
    let month = rtnArr[0] === '' ? (min ? 1 : 12) : rtnArr[1] < 1 ? 1 : rtnArr[1] > 12 ? 12 : rtnArr[1]
    rtnArr[1] = Number(month)
    // 日期
    let dayMax = getMonthLastDate(rtnArr[0], month).getDate(),
        day = rtnArr[2] === '' ? (min ? 1 : dayMax) : rtnArr[2] < 1 ? 1 : rtnArr[2] > dayMax ? dayMax : rtnArr[2]
    rtnArr[2] = Number(day)
    // 时
    rtnArr[3] = rtnArr[3] === '' ? (min ? 0 : 23) : rtnArr[3] < 0 ? 0 : rtnArr[3] > 23 ? 23 : Number(rtnArr[3])
    // 分
    rtnArr[4] = rtnArr[4] === '' ? (min ? 0 : 59) : rtnArr[4] < 0 ? 0 : rtnArr[4] > 59 ? 59 : Number(rtnArr[4])
    // 秒
    rtnArr[5] = rtnArr[5] === '' ? (min ? 0 : 59) : rtnArr[5] < 0 ? 0 : rtnArr[5] > 59 ? 59 : Number(rtnArr[5])
    let date = Number(`${rtnArr[0]}${formatNumber(rtnArr[1])}${formatNumber(rtnArr[2])}`),
        time = Number(`${formatNumber(rtnArr[3])}${formatNumber(rtnArr[4])}${formatNumber(rtnArr[5])}`)
    rtnArr.push(date, time)
  } else {
    rtnArr = ''
  }
  return rtnArr
}

function fmtDfltVal(str) {
  let arr = str.split(/[-:\s+]/g),
      reg = /^[0-9]*$/
  let rtnArr = []
  arr.forEach(item => {
    if(reg.test(item)) rtnArr.push(item)
  })
  if(rtnArr[0]) {
    for(let i = 0, len = 6 - rtnArr.length; i < len; i++) {
      rtnArr.push('')
    }
    // 年份
    rtnArr[0] = Number(rtnArr[0])
    // 月份
    rtnArr[1] = (rtnArr === '' || rtnArr[1] < 1 || rtnArr[1] > 12) ? currMonth : Number(rtnArr[1])
    // 日期
    let dayMax = getMonthLastDate(rtnArr[0], rtnArr[1]).getDate()
    rtnArr[2] = (rtnArr === '' || rtnArr[2] < 1 || rtnArr[2] > dayMax) ? currDay : Number(rtnArr[2])
    // 时
    rtnArr[3] = (rtnArr[3] === '' || rtnArr[3] < 0 || rtnArr[3] > 23) ? 0 : Number(rtnArr[3])
    // 分
    rtnArr[4] = (rtnArr[4] === '' || rtnArr[4] < 0 || rtnArr[4] > 59) ? 0 : Number(rtnArr[4])
    // 秒
    rtnArr[5] = (rtnArr[5] === '' || rtnArr[5] < 0 || rtnArr[5] > 59) ? 0 : Number(rtnArr[5])
  } else {
    rtnArr = ''
  }
  return rtnArr
}

let { formatDate, getMonthFirstDate, getMonthLastDate, formatNumber, } = wx.$util

// 设置当前日期索引
let currDate = new Date(),
    currFirst = getMonthFirstDate(),
    currYear = currDate.getFullYear(),
    currMonth = currDate.getMonth() + 1,
    currDay = currDate.getDate(),
    currIdx = currFirst.getDay() + currDate.getDate() - 1

let hours = [ ...(new Array(24)).keys() ],
    minutes = [ ...(new Array(60)).keys() ],
    seconds = [ ...(new Array(60)).keys() ]

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 弹出弹层标识
    flag: {
      type: Boolean,
      value: false,
      observer(newVal, oldVal) {
        let { finalYear, finalMonth, finalDay, finalIdx, finalH, finalM, finalS, year, month, } = this.data,
            obj = {
              show: true,
              changeFlag: true,
              selYear: finalYear,
              selMonth: finalMonth,
              selDay: finalDay,
              selIdx: finalIdx,
              hIdx: finalH,
              mIdx: finalM,
              sIdx: finalS,
            },
            needSetDateList = false
        if(!finalMonth && month && (year !== currYear || month !== currMonth)) {  // 没有确认选择日期，跳回当前月份日历
          obj.year = currYear
          obj.month = currMonth
          needSetDateList = true
        } else if(finalMonth && (year !== finalYear || month !== finalMonth)) { // 确认选择日期，跳回选好的月份
          obj.year = finalYear
          obj.month = finalMonth
          needSetDateList = true
        }
        this.setData(obj)
        if(needSetDateList) this.setDateList()
      },
    },
    // 重置日历标识
    reset: {
      type: Boolean,
      value: false,
      observer(newVal, oldVal) {
        this.setData({
          selYear: 0,
          selMonth: 0,
          selDay: 0,
          selIdx: null,
          hIdx: 0,
          mIdx: 0,
          sIdx: 0,
          finalYear: 0,
          finalMonth: 0,
          finalDay: 0,
          finalIdx: null,
          finalH: 0,
          finalM: 0,
          finalS: 0,
          resetFlag: !this.data.resetFlag,
          dfltVal: '',
        })
        this.triggerEvent('select', '')
      },
    },
    // 自定义格式
    fmt: {
      type: String,
      value: 'yyyy-MM-dd',
      observer(newVal, oldVal) {
        let str = 'yyyy-MM-dd HH:mm:ss',
            obj = {
              format: 'yyyy-MM-dd',
            }
        if(newVal && !str.indexOf(newVal)) obj.format = newVal
        obj.time = obj.format.indexOf('HH') > -1
        this.setData(obj)
      },
    },
    // 初始值
    value: {
      type: String,
      value: '',
      observer(newVal, oldVal) {
        if(newVal) {
          let val = fmtDfltVal(newVal)
          if(val) {
            this.setData({
              dfltVal: val,
            });
            this.setDateList(...val)
          }
        }
      },
    },
    // 最小日期(时间)
    min: {
      type: String,
      value: '',
      observer(newVal, oldVal) {
        if(newVal) {
          let rtn = getDateArr(newVal, true)
          if(rtn) {
            this.setData({
              minVal: rtn,
            })
          }
        }
      },
    },
    // 最大日期(时间)
    max: {
      type: String,
      value: '',
      observer(newVal, oldVal) {
        if(newVal) {
          let rtn = getDateArr(newVal, false)
          if(rtn) {
            this.setData({
              maxVal: rtn,
            })
          }
        }
      },
    },
  },

  // 监听
  observers: {
    resetFlag(val) {
      this.initData()
    },
  },

  /**
   * 组件的初始数据
   */
  data: {
    show: false,
    format: 'yyyy-MM-dd',

    dayList: ['日', '一', '二', '三', '四', '五', '六', ],
    year: '',
    month: '',
    dateList: [],
    start: 0,
    end: 0,

    // // 当前日期
    // currYear: currYear,
    // currMonth: currMonth,
    // currDay: currDay,
    // currIdx: currIdx,

    // 选中的日期
    selYear: 0,
    selMonth: 0,
    selDay: 0,
    selIdx: null,

    // 最终确认选择的日期
    finalYear: 0,
    finalMonth: 0,
    finalDay: 0,
    finalIdx: null,
    finalH: 0,
    finalM: 0,
    finalS: 0,

    // 日期/时间标识
    changeFlag: true,

    // 时间
    time: false,
    hours,
    minutes,
    seconds,
    hIdx: 0,
    mIdx: 0,
    sIdx: 0,

    // 初始默认值
    dfltVal: '',

    // 最小/大日期
    minVal: '',
    maxVal: '',

    // 重置标识
    resetFlag: false,
  },

  // 生命周期
  lifetimes: {
    created() {},
    attached() {
      this.setData({
        resetFlag: !this.data.resetFlag,
      })
    },
    ready() {},
    moved() {},
    detached() {},
    error() {},
  },

  /**
   * 组件的方法列表
   */
  methods: {
    // 初始化参数
    initData() {
      let dfltVal = this.data.dfltVal,
          year = currYear,
          month = currMonth,
          day = currDay,
          obj = {}

      obj.year = dfltVal ? dfltVal[0] : year
      obj.month = dfltVal ? dfltVal[1] : month

      this.setData(obj)
      // 设置日历选项列表
      dfltVal ? this.setDateList(...dfltVal) : this.setDateList()
    },
    // 设置日历选项列表
    setDateList(dfltY, dfltM, dfltD, dfltHi, dfltMi, dfltSi) {
      let { year, month, minVal, maxVal, } = this.data,
          first = getMonthFirstDate(year, month),
          last = getMonthLastDate(year, month),
          preLast = getMonthLastDate(year, month - 1),
          dayLen = last.getDate(),
          dfltIdx = null

      let list = [ ...(new Array(dayLen + 1)).keys() ],
          preLastDate = preLast.getDate(),
          firstDay = first.getDay()
      list.shift()
      for(let i = preLastDate, len = preLastDate - firstDay; i > len; i--) {
        list.unshift(i)
      }
      for(let i = 1, len = 43 - list.length; i < len; i++) {
        list.push(i)
      }

      let dList = [],
          start = firstDay,
          end = firstDay + dayLen - 1,
          preM = preLast.getMonth() + 1,
          preMY = preM === 12 ? (year - 1) : year,
          nextM = month === 12 ? 1 : (month + 1),
          nextMY = month === 12 ? (year + 1) : year
      if(minVal) minVal = minVal[6]
      if(maxVal) maxVal = maxVal[6]
      list.forEach((item, i) => {
        let obj = {
          day: item,
          month,
          year,
          curr: false,
          thismonth: false,
          outrange: false,
        }
        if(i >= start && i <= end) {  // 本月
          obj.thismonth = true
          if(item === currDay && month === currMonth && year === currYear) obj.curr = true
        } else if(i < start) {  // 上个月
          obj.year = preMY
          obj.month = preM
        } else if(i > end) {  // 下个月
          obj.year = nextMY
          obj.month = nextM
        }

        // 超出可选范围
        let compVal = Number(`${obj.year}${formatNumber(obj.month)}${formatNumber(obj.day)}`)
        if(minVal && compVal <= minVal) {
          if(compVal === minVal) obj.min = true
          else obj.outrange = true
        } else if(maxVal && compVal >= maxVal) {
          if(compVal === maxVal) obj.max = true
          else obj.outrange = true
        }

        dList.push(obj)

        // 有默认值，设置默认值
        if(dfltY !== undefined && obj.day === dfltD && obj.month === dfltM && obj.year === dfltY) dfltIdx = i
      })

      let obj = {}
      if(dfltIdx !== null) {
        obj = {
          selYear: dfltY,
          selMonth: dfltM,
          selDay: dfltD,
          selIdx: dfltIdx,
          hIdx: dfltHi,
          mIdx: dfltMi,
          sIdx: dfltSi,
          finalYear: dfltY,
          finalMonth: dfltM,
          finalDay: dfltD,
          finalIdx: dfltIdx,
          finalH: dfltHi,
          finalM: dfltMi,
          finalS: dfltSi,
        }
      }

      this.setData({
        dateList: dList,
        ...obj,
      })
    },

    // 关闭
    closePopup(e) {
      this.setData({
        show: false,
      })
    },
    // 确定
    select(e) {
      let { selYear, selMonth, selDay, selIdx, hIdx, mIdx, sIdx, format, } = this.data
      if(!selMonth) {
        selYear = currYear
        selMonth = currMonth
        selDay = currDay
        selIdx = currIdx
      }

      let date = new Date(selYear, selMonth - 1, selDay, hIdx, mIdx, sIdx),
          val = formatDate(date, format)

      this.setData({
        finalYear: selYear,
        finalMonth: selMonth,
        finalDay: selDay,
        finalIdx: selIdx,
        finalH: hIdx,
        finalM: mIdx,
        finalS: sIdx,
      })
      this.triggerEvent('select', val)
      this.closePopup()
    },
    // 上个月
    prevMonth(e) {
      let { year, month } = this.data
      if(month === 1) {
        month = 12
        year--
      } else {
        month--
      }
      this.setData({
        year,
        month,
      })
      this.setDateList()
    },
    // 下个月
    nextMonth(e) {
      let { year, month } = this.data
      if(month === 12) {
        month = 1
        year++
      } else {
        month++
      }
      this.setData({
        year,
        month,
      })
      this.setDateList()
    },
    // 上一年
    prevYear(e) {
      let year = this.data.year
      if(year < 2) return
      this.setData({
        year: --year,
      })
      this.setDateList()
    },
    // 下一年
    nextYear(e) {
      let year = this.data.year
      this.setData({
        year: ++year,
      })
      this.setDateList()
    },
    // 选择时间/返回日期
    change(e) {
      this.setData({
        changeFlag: !this.data.changeFlag,
      })
    },

    // 选中某个日期
    selectDate(e) {
      let { idx, item, } = e.currentTarget.dataset,
          { year, month, minVal, maxVal, hIdx, mIdx, sIdx, } = this.data
      if(item.outrange) {
        wx.$toast('该日期不在可选范围内！')
        return
      }
      if(!item.thismonth) { // 选了上/下月，重置日历列表
        (item.year < year || (item.year === year && item.month < month)) ? this.prevMonth() : this.nextMonth()
        year = this.data.year
        month = this.data.month
      }
      let obj = {}
      // 边界值处理
      if(item.min || item.max) {
        let minMax = item.min ? minVal : maxVal,
            time = minMax[7],
            compTime = Number(`${formatNumber(hIdx)}${formatNumber(mIdx)}${formatNumber(sIdx)}`)
        if((item.min && time > compTime) || (item.max && time < compTime)) {
          obj = {
            hIdx: minMax[3],
            mIdx: minMax[4],
            sIdx: minMax[5],
          }
        }
      }

      this.setData({
        selYear: year,
        selMonth: month,
        selDay: item.day,
        selIdx: idx,
        ...obj,
      })
    },
    // 选中某个时间
    selectTime(e) {
      let { idx, key, } = e.currentTarget.dataset,
          { minVal, maxVal, selIdx, dateList, hIdx, mIdx, sIdx, } = this.data,
          selItem = '',
          obj = {},
          flag = false

      if(selIdx !== null) selItem = dateList[selIdx]
      if(selItem && (selItem.min || selItem.max)) {
        if(key === 'hIdx') {
          if(minVal[3] >= idx) {
            flag = true
            if(minVal[3] === idx) {
              flag = false
              if(minVal[4] >= mIdx) {
                obj.mIdx = minVal[4]
                if(minVal[5] > sIdx) obj.sIdx = minVal[5]
              }
            }
          }
          else if(maxVal[3] <= idx) {
            flag = true
            if(maxVal[3] === idx) {
              flag = false
              if(maxVal[4] <= mIdx) {
                obj.mIdx = maxVal[4]
                if(maxVal[5] < sIdx) obj.sIdx = maxVal[5]
              }
            }
          }
        } else if(key === 'mIdx') {
          if(minVal[3] === hIdx && minVal[4] >= idx) {
            flag = true
            if(minVal[4] === idx) {
              flag = false
              if(minVal[5] > sIdx) obj.sIdx = minVal[5]
            }
          }
          else if(maxVal[3] === hIdx && maxVal[4] <= idx) {
            flag = true
            if(maxVal[4] === idx) {
              flag = false
              if(maxVal[5] < sIdx) obj.sIdx = maxVal[5]
            }
          }
        } else if(key === 'sIdx') {
          if(minVal[3] === hIdx && minVal[4] === mIdx && minVal[5] > idx) flag = true
          else if(maxVal[3] === hIdx && maxVal[4] === mIdx && maxVal[5] < idx) flag = true
        }
      }

      if(flag) return
      this.setData({
        [key]: idx,
        ...obj,
      })
    },
  },
})
